"""
这是一个文件拖入窗口的全屏遮罩，同时会显示图标和文字，请在主窗口内实例化 DropMask
注意该窗口实例化需要在窗体 setupUi 之后

"""

from PySide6.QtCore import QEasingCurve, QEvent, QPropertyAnimation, Qt, Signal
from PySide6.QtGui import QColor, QDragLeaveEvent, QResizeEvent, QDragEnterEvent
from PySide6.QtWidgets import (
    QDialog,
    QFrame,
    QGraphicsDropShadowEffect,
    QGraphicsOpacityEffect,
    QHBoxLayout,
    QSizePolicy,
    QVBoxLayout,
    QWidget,
    QStyle,
    QLabel,
)

# 允许拖入的文件后缀
SUFFIX: list[str] = [".vmd", '.pmx']


class DropMask(QDialog):
    """Dialog box base class with a mask"""

    droped_file_url = Signal(str)

    def __init__(self, parent, title: str):
        super().__init__(parent=parent)
        self._hBoxLayout = QHBoxLayout(self)
        self.windowMask = QWidget(self)
        self.setAcceptDrops(True)

        # 设置在最顶层
        self.setWindowModality(Qt.WindowModality.ApplicationModal)

        # dialog box in the center of mask, all widgets take it as parent
        self.widget = QFrame(self)
        self.v_layout = QVBoxLayout()
        self.v_layout.setAlignment(Qt.AlignmentFlag.AlignCenter)
        self.v_layout2 = QVBoxLayout()
        self.v_layout2.setAlignment(Qt.AlignmentFlag.AlignCenter)
        self.biggest_layout = QVBoxLayout()

        self.icon_widget = QLabel()
        self.icon_widget.setPixmap(
            self.style().standardIcon(QStyle.SP_DialogApplyButton).pixmap(108, 108)
        )
        self.icon_widget.setAlignment(Qt.AlignmentFlag.AlignCenter)
        self.icon_widget.setFixedSize(108, 108)
        self.icon_widget.setSizePolicy(
            QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed
        )
        self.title_label = QLabel()
        self.title_label.setText(title)
        self.title_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
        # 放大字体，设为衬线字体
        self.title_label.setStyleSheet("font-size: 30px;")

        self.v_layout.addWidget(self.icon_widget)
        self.v_layout2.addWidget(self.title_label)

        self.biggest_layout.addLayout(self.v_layout)
        self.biggest_layout.addLayout(self.v_layout2)

        self.widget.setLayout(self.biggest_layout)

        self.setWindowFlags(Qt.WindowType.FramelessWindowHint)
        self.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground)
        self.setGeometry(0, 0, parent.width(), parent.height())

        self.windowMask.resize(self.size())

        self._hBoxLayout.addWidget(self.widget, 1, Qt.AlignmentFlag.AlignCenter)
        self.set_shadow_effect()
        self.set_mask_color(QColor(0, 0, 0, 75))

        self.window().installEventFilter(self)

    def set_shadow_effect(
            self, blur_radius=60, offset=(0, 10), color=QColor(0, 0, 0, 50)
    ):
        """add shadow to dialog"""
        shadow_effect = QGraphicsDropShadowEffect(self.widget)
        shadow_effect.setBlurRadius(blur_radius)
        shadow_effect.setOffset(*offset)
        shadow_effect.setColor(color)
        # self.widget.setGraphicsEffect(None)
        self.widget.setGraphicsEffect(shadow_effect)

    def set_mask_color(self, color: QColor):
        """set the color of mask"""
        self.windowMask.setStyleSheet(f""" 
            background: rgba({color.red()}, {color.blue()}, {color.green()}, {color.alpha()})
        """)

    def showEvent(self, e):
        """fade in"""
        opacity_effect = QGraphicsOpacityEffect(self)
        self.setGraphicsEffect(opacity_effect)
        opacity_ani = QPropertyAnimation(opacity_effect, b"opacity", self)
        opacity_ani.setStartValue(0)
        opacity_ani.setEndValue(1)
        opacity_ani.setDuration(200)
        opacity_ani.setEasingCurve(QEasingCurve.Type.InSine)
        opacity_ani.finished.connect(opacity_effect.deleteLater)
        opacity_ani.start()
        super().showEvent(e)

    def closeEvent(self, e):
        """fade out"""
        # self.widget.setGraphicsEffect(None)
        opacity_effect = QGraphicsOpacityEffect(self)
        self.setGraphicsEffect(opacity_effect)
        opacity_ani = QPropertyAnimation(opacity_effect, b"opacity", self)
        opacity_ani.setStartValue(1)
        opacity_ani.setEndValue(0)
        opacity_ani.setDuration(100)
        opacity_ani.setEasingCurve(QEasingCurve.Type.OutCubic)
        opacity_ani.finished.connect(self.deleteLater)
        opacity_ani.start()
        e.ignore()

    def resizeEvent(self, e):
        self.windowMask.resize(self.size())

    def eventFilter(self, obj, e: QEvent):
        if obj is self.window():
            if e.type() == QEvent.Type.Resize:
                re = QResizeEvent(e)
                self.resize(re.size())

        return super().eventFilter(obj, e)

    def dragEnterEvent(self, e):
        file_text: str = e.mimeData().text()
        if e.mimeData().hasText():
            if any(file_text.endswith(x) for x in SUFFIX):
                self.icon_widget.setPixmap(
                    self.style()
                    .standardIcon(QStyle.SP_DialogApplyButton)
                    .pixmap(64, 64)
                )
                # 将图标设置为居中
                self.icon_widget.setFixedSize(108, 108)
                self.title_label.setText("松开鼠标放入文件")
            else:
                self.icon_widget.setPixmap(
                    self.style()
                    .standardIcon(QStyle.SP_DialogCancelButton)
                    .pixmap(64, 64)
                )
                self.icon_widget.setFixedSize(108, 108)
                self.title_label.setText(f"文件必须是{'或'.join(SUFFIX)}文件")
            e.accept()
        else:
            self.hide()
            e.ignore()

    def dragLeaveEvent(self, event: QDragLeaveEvent) -> None:
        # 当文件移动出窗口的时候，隐藏窗口
        self.hide()

    def dropEvent(self, e):
        path = e.mimeData().urls()[0].toLocalFile()
        self.droped_file_url.emit(path)
        self.hide()


if __name__ == "__main__":
    from PySide6.QtWidgets import QApplication


    class MyWindow(QWidget):
        def __init__(self):
            super().__init__()
            self.resize(800, 600)
            self.setAcceptDrops(True)
            self.setWindowTitle("DropMask Test")
            self.dialog_mask = DropMask(self, "拖入文件")
            self.dialog_mask.droped_file_url.connect(lambda x: print(x))
            self.dialog_mask.hide()

        def dragEnterEvent(self, e: QDragEnterEvent):
            if e.mimeData().hasText():
                self.dialog_mask.show()

        # 窗体大小发生改变触发事件
        def resizeEvent(self, event):
            self.resize_mask()

        def resize_mask(self) -> None:
            self.dialog_mask.resize(self.width(), self.height())


    app = QApplication([])
    mask = MyWindow()
    mask.show()
    app.exec()
